home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIAppletalk.cp < prev    next >
Encoding:
Text File  |  1994-05-01  |  18.6 KB  |  967 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                    -    Grand Unified Socket Interface
  3. File        :    GUSIAppleTalk.cp    -    Appletalk Sockets
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIAppletalk.cp,v $
  8. Revision 1.2  1994/05/01  23:29:28  neeri
  9. Enable recvfrom with non-NULL from address.
  10.  
  11. Revision 1.1  1994/02/25  02:28:11  neeri
  12. Initial revision
  13.  
  14. Revision 0.18  1993/12/30  00:00:00  neeri
  15. Fiddle with select()
  16.  
  17. Revision 0.17  1993/11/17  00:00:00  neeri
  18. Delay opening AppleTalk services
  19.  
  20. Revision 0.16  1993/09/01  00:00:00  neeri
  21. Throw out nonbreaking spaces
  22.  
  23. Revision 0.15  1993/02/07  00:00:00  neeri
  24. New configuration technique
  25.  
  26. Revision 0.14  1993/01/17  00:00:00  neeri
  27. Handle user interrupts more carefully.
  28.  
  29. Revision 0.13  1992/12/07  00:00:00  neeri
  30. Use flags
  31.  
  32. Revision 0.12  1992/10/05  00:00:00  neeri
  33. I was a teenage NBP werewolf
  34.  
  35. Revision 0.11  1992/09/13  00:00:00  neeri
  36. Always complete write
  37.  
  38. Revision 0.10  1992/09/07  00:00:00  neeri
  39. Implement ioctl()
  40.  
  41. Revision 0.9  1992/08/10  00:00:00  neeri
  42. Improve select()
  43.  
  44. Revision 0.8  1992/07/28  00:00:00  neeri
  45. Separate creating symaddrs from registering them
  46.  
  47. Revision 0.7  1992/07/26  00:00:00  neeri
  48. Error in using memccpy()
  49.  
  50. Revision 0.6  1992/07/21  00:00:00  neeri
  51. Support symbolic addresses
  52.  
  53. Revision 0.5  1992/07/13  00:00:00  neeri
  54. Make AppleTalkSockets available to other socket classes.
  55.  
  56. Revision 0.4  1992/05/18  00:00:00  neeri
  57. Out of band data
  58.  
  59. Revision 0.3  1992/05/18  00:00:00  neeri
  60. Basic functions work
  61.  
  62. Revision 0.2  1992/05/12  00:00:00  neeri
  63. NBP stuff
  64.  
  65. Revision 0.1  1992/05/10  00:00:00  neeri
  66. ADSPStreams
  67.  
  68. *********************************************************************/
  69.  
  70. #include "GUSI_P.h"
  71.  
  72. #include <Errors.h>
  73. #include <ADSP.h>
  74. #include <Devices.h>
  75. #include <GestaltEqu.h>
  76. #include <PLStringFuncs.h>
  77.  
  78. #include <Strings.h>
  79.  
  80. #include <sys/types.h>
  81.  
  82. class AtlkSymAddr;
  83.  
  84. class AppleTalkSocketDomain : public SocketDomain {
  85.     short                        dspRefNum;
  86.     
  87.     void                        DoMPPOpen();
  88. public:
  89.     AppleTalkSocketDomain();
  90.     
  91.     AddrBlock                node;
  92.     
  93.                 short            GetDSP();        
  94.                 Boolean        Validate();
  95.     virtual    Socket *     socket(int type, short protocol);
  96.     virtual int choose(
  97.                         int         type, 
  98.                         char *     prompt, 
  99.                         void *     constraint,        
  100.                         int         flags,
  101.                          void *     name, 
  102.                         int *     namelen);
  103. };
  104.  
  105. class AppleTalkSocket : public Socket    {        // That's what this file's all about
  106.     friend class AppleTalkSocketDomain;
  107. protected:
  108.     Boolean            nonblocking;
  109.     Boolean            ownSocket;
  110.     Boolean            readShutDown;
  111.     Boolean            writeShutDown;
  112.     u_char            socket;
  113.     AddrBlock        peer;
  114.     AtlkSymAddr *    symaddr;
  115.  
  116.                     AppleTalkSocket(u_char sock = 0);
  117.  
  118.     virtual         ~AppleTalkSocket();
  119. public:
  120.     virtual int    bind(void * name, int namelen);
  121.     virtual int getsockname(void * name, int * namelen);
  122.     virtual int getpeername(void *name, int *namelen);
  123.     virtual int    fcntl(unsigned int cmd, int arg);
  124.     virtual int    ioctl(unsigned int request, void *argp);
  125. };
  126.  
  127. struct ADSPSockBuffers {
  128.     enum {qSize    =    4150};
  129.  
  130.     u_char    attnBuf[attnBufSize];
  131.     u_char    sendBuf[qSize];
  132.     u_char    recvBuf[qSize];
  133. };
  134.  
  135. typedef ADSPSockBuffers * ADSPBufPtr;
  136.  
  137. class ADSPSocket : public AppleTalkSocket {
  138.     friend class AppleTalkSocketDomain;
  139.  
  140.                     ADSPSocket(u_char sock = 0);
  141.  
  142.     TRCCB    *        ccb;
  143.     DSPPBPtr        pb;
  144.     ADSPBufPtr    bufs;
  145.  
  146.     int            Init();
  147.     void            UnInit(Boolean abort);
  148.     Boolean        Waiting();
  149.     Boolean        Up();
  150. public:
  151.     virtual int listen(int qlen);
  152.     virtual int connect(void * address, int addrlen);
  153.     virtual Socket * accept(void * address, int * addrlen);
  154.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  155.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  156.     virtual int shutdown(int how);
  157.     virtual int    ioctl(unsigned int request, void *argp);
  158.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  159.  
  160.     virtual         ~ADSPSocket();
  161. };
  162.  
  163. class AtlkSymAddr {
  164.     struct NTE    {
  165.         Ptr            next;
  166.         AddrBlock    addr;
  167.         char            rsrv;
  168.         char            name;
  169.     };
  170.  
  171.     NTE *        nte;
  172.     Boolean    legit;
  173. public:
  174.     AtlkSymAddr(const EntityName & name);
  175.  
  176.     ~AtlkSymAddr();
  177.  
  178.     void Register(u_char socket);
  179. };
  180.  
  181. int AtlkLookup(const EntityName & name, AddrBlock * addr);
  182.  
  183. AppleTalkSocketDomain    AppleTalkSockets;
  184. const AddrBlock            NoFilter    =    {0, 0, 0};
  185.  
  186. /************************ AppleTalkSocket members ************************/
  187.  
  188. AppleTalkSocket::AppleTalkSocket(u_char sock)
  189. {
  190.     socket            =    sock;
  191.     ownSocket        =    !sock;
  192.     nonblocking        =    false;
  193.     readShutDown    =    false;
  194.     writeShutDown    =    false;
  195.     symaddr            =    nil;
  196.     peer                =    NoFilter;
  197. }
  198.  
  199. AppleTalkSocket::~AppleTalkSocket()
  200. {
  201.     if (socket && ownSocket)    {
  202.         MPPParamBlock    mpp;
  203.  
  204.         mpp.DDP.socket    =    socket;
  205.  
  206.         PCloseSkt(&mpp, false);
  207.     }
  208.  
  209.     if (symaddr)
  210.         delete symaddr;
  211. }
  212.  
  213. int AppleTalkSocket::fcntl(unsigned int cmd, int arg)
  214. {
  215.     switch (cmd)    {
  216.     case F_GETFL:
  217.         if (nonblocking)
  218.             return FNDELAY;
  219.         else
  220.             return 0;
  221.     case F_SETFL:
  222.         if (arg & FNDELAY)
  223.             nonblocking = true;
  224.         else
  225.             nonblocking = false;
  226.  
  227.         return 0;
  228.     default:
  229.         return GUSI_error(EOPNOTSUPP);
  230.     }
  231. }
  232.  
  233. int AppleTalkSocket::ioctl(unsigned int request, void *argp)
  234. {
  235.     switch (request)    {
  236.     case FIONBIO:
  237.         nonblocking    =    (Boolean) *(long *) argp;
  238.  
  239.         return 0;
  240.     default:
  241.         return GUSI_error(EOPNOTSUPP);
  242.     }
  243. }
  244.  
  245. int AppleTalkSocket::bind(void *sa_name, int)
  246. {
  247.  
  248.     switch (*(short *) sa_name)    {
  249.     case AF_APPLETALK:
  250.         {
  251.             struct sockaddr_atlk *    addr = (struct sockaddr_atlk *) sa_name;
  252.  
  253.             if (socket || !addr->addr.aSocket)
  254.                 return GUSI_error(EINVAL);
  255.  
  256.             socket        =    addr->addr.aSocket;
  257.             ownSocket    =    false;
  258.         }
  259.         break;
  260.     case ATALK_SYMADDR:
  261.         {
  262.             struct sockaddr_atlk_sym *    addr = (struct sockaddr_atlk_sym *) sa_name;
  263.  
  264.             symaddr        =    new AtlkSymAddr(addr->name);
  265.  
  266.             if (errno)    {
  267.                 delete symaddr;
  268.                 symaddr = nil;
  269.  
  270.                 return -1;
  271.             }
  272.         }
  273.         break;
  274.     default:
  275.         return GUSI_error(EAFNOSUPPORT);
  276.     }
  277.  
  278.     return 0;
  279. }
  280.  
  281. int AppleTalkSocket::getsockname(void *name, int *namelen)
  282. {
  283.     struct sockaddr_atlk    addr;
  284.  
  285.     addr.family            =    AF_APPLETALK;
  286.     addr.addr            =    AppleTalkSockets.node;
  287.     addr.addr.aSocket    =    socket;
  288.  
  289.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_atlk)));
  290.  
  291.     return 0;
  292. }
  293.  
  294. int AppleTalkSocket::getpeername(void *name, int *namelen)
  295. {
  296.     struct sockaddr_atlk    addr;
  297.  
  298.     if (!peer.aNet && !peer.aNode && !peer.aSocket)
  299.         return GUSI_error(ENOTCONN);
  300.  
  301.     addr.family            =    AF_APPLETALK;
  302.     addr.addr            =    peer;
  303.  
  304.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(struct sockaddr_atlk)));
  305.  
  306.     return 0;
  307. }
  308.  
  309. /********************* ADSPSocket members *********************/
  310.  
  311. ADSPSocket::ADSPSocket(u_char sock)
  312.     :    AppleTalkSocket(sock)
  313. {
  314.     ccb            =    nil;
  315.     pb                =    nil;
  316.     bufs             =    nil;
  317.  
  318.     if (!AppleTalkSockets.GetDSP())
  319.         GUSI_error(EPFNOSUPPORT);                    // Just an educated guess
  320. }
  321.  
  322. ADSPSocket::~ADSPSocket()
  323. {
  324.     UnInit(false);
  325. }
  326.  
  327. inline Boolean ADSPSocket::Waiting()
  328. {
  329.     return pb->ioResult == 1 && !(ccb->userFlags & (eClosed | eTearDown));
  330. }
  331.  
  332. inline Boolean ADSPSocket::Up()
  333. {
  334.     return !(ccb->userFlags & (eClosed | eTearDown));
  335. }
  336.  
  337. int ADSPSocket::listen(int)
  338. {
  339.     if (ccb)
  340.         return GUSI_error(EISCONN);
  341.  
  342.     ccb     =    new TRCCB;
  343.     if (!ccb)
  344.         goto memErrCCB;
  345.  
  346.     pb        =    new DSPParamBlock;
  347.     if (!pb)
  348.         goto memErrPB;
  349.  
  350.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  351.     pb->csCode                            =    dspCLInit;
  352.     pb->u.initParams.ccbPtr            =    ccb;
  353.     pb->u.initParams.localSocket    =    socket;
  354.  
  355.     if (PBControlSync(ParmBlkPtr(pb)))
  356.         goto memErr;
  357.  
  358.     socket        =    pb->u.initParams.localSocket;
  359.  
  360.     if (symaddr)
  361.         symaddr->Register(socket);
  362.  
  363.     pb->csCode                                =    dspCLListen;
  364.     pb->ioCompletion                        =    nil;
  365.     pb->u.openParams.filterAddress    =    NoFilter;
  366.  
  367.     PBControlAsync(ParmBlkPtr(pb));
  368.  
  369.     return 0;
  370.  
  371. memErr:
  372.     delete pb;
  373.     pb    =    nil;
  374. memErrPB:
  375.     delete ccb;
  376.     ccb    =    nil;
  377. memErrCCB:
  378.     return GUSI_error(ENOMEM);
  379. }
  380.  
  381. int ADSPSocket::Init()
  382. {
  383.     if (ccb)
  384.         if (pb->csCode == dspOpen && pb->ioResult && pb->ioResult != 1)
  385.             return 0;                            // Second chance for lose on open
  386.         else
  387.             return GUSI_error(EISCONN);    // Got a live un', don't reconnect
  388.  
  389.     ccb     =    new TRCCB;
  390.     if (!ccb)
  391.         goto memErrCCB;
  392.  
  393.     pb        =    new DSPParamBlock;
  394.     if (!pb)
  395.         goto memErrPB;
  396.  
  397.     bufs    =    new ADSPSockBuffers;
  398.     if (!bufs)
  399.         goto memErrBufs;
  400.  
  401.     pb->ioCRefNum                        =    AppleTalkSockets.GetDSP();
  402.     pb->csCode                            =    dspInit;
  403.     pb->u.initParams.ccbPtr            =    ccb;
  404.     pb->u.initParams.userRoutine    =    nil;
  405.     pb->u.initParams.sendQSize        =    bufs->qSize;
  406.     pb->u.initParams.sendQueue        =    bufs->sendBuf;
  407.     pb->u.initParams.recvQSize        =    bufs->qSize;
  408.     pb->u.initParams.recvQueue        =    bufs->recvBuf;
  409.     pb->u.initParams.attnPtr        =    bufs->attnBuf;
  410.     pb->u.initParams.localSocket    =    socket;
  411.  
  412.     if (!PBControlSync(ParmBlkPtr(pb)))    {
  413.         socket        =    pb->u.initParams.localSocket;
  414.  
  415.         if (symaddr)
  416.             symaddr->Register(socket);
  417.  
  418.         return 0;
  419.     }
  420.  
  421.     delete bufs;
  422.     bufs    =    nil;
  423. memErrBufs:
  424.     delete pb;
  425.     pb        =    nil;
  426. memErrPB:
  427.     delete ccb;
  428.     ccb    =    nil;
  429. memErrCCB:
  430.     return GUSI_error(ENOMEM);
  431. }
  432.  
  433. void ADSPSocket::UnInit(Boolean abort)
  434. {
  435.     if (ccb && pb)    {
  436.         pb->csCode                    =    bufs ? dspRemove : dspCLRemove;
  437.         pb->u.closeParams.abort    =    abort;
  438.  
  439.         PBControlSync(ParmBlkPtr(pb));
  440.     }
  441.  
  442.     if (ccb)
  443.         delete ccb;
  444.     if (pb)
  445.         delete pb;
  446.     if (bufs)
  447.         delete bufs;
  448.     
  449.     ccb    =    nil;
  450.     pb        =    nil;
  451.     bufs    =    nil;
  452. }
  453.  
  454. int ADSPSocket::connect(void *sa_name, int)
  455. {
  456.     switch (*(short *) sa_name)    {
  457.     case AF_APPLETALK:
  458.         {
  459.             sockaddr_atlk *    addr     =    (struct sockaddr_atlk *) sa_name;
  460.             peer                            =    addr->addr;
  461.         }
  462.         break;
  463.     case ATALK_SYMADDR:
  464.         {
  465.             struct sockaddr_atlk_sym *    addr     =     (struct sockaddr_atlk_sym *) sa_name;
  466.  
  467.             if (AtlkLookup(addr->name, &peer))
  468.                 return -1;
  469.         }
  470.         break;
  471.     default:
  472.         return GUSI_error(EAFNOSUPPORT);
  473.     }
  474.  
  475.     if (Init())
  476.         return -1;
  477.  
  478.     pb->csCode                                =    dspOpen;
  479.     pb->ioCompletion                        =    nil;
  480.     pb->u.openParams.remoteAddress    =    peer;
  481.     pb->u.openParams.filterAddress    =    NoFilter;
  482.     pb->u.openParams.ocMode                =    ocRequest;
  483.     pb->u.openParams.ocInterval        =    0;
  484.     pb->u.openParams.ocMaximum            =    0;
  485.  
  486.     PBControlAsync(ParmBlkPtr(pb));
  487.  
  488.     if (nonblocking)
  489.         return GUSI_error(EINPROGRESS);
  490.  
  491.     SAFESPIN(Waiting(), SP_MISC, 0);
  492.  
  493.     if (errno)    {
  494.         UnInit(true);
  495.         
  496.         return -1;
  497.     } else if (pb->ioResult == noErr) {
  498.         return 0;
  499.     } else
  500.         return GUSI_error(ECONNREFUSED);
  501. }
  502.  
  503. Socket * ADSPSocket::accept(void * address, int * addrlen)
  504. {
  505.     ADSPSocket *    newsock;
  506.     sockaddr_atlk    addr;
  507.  
  508.     if (!pb || pb->csCode != dspCLListen)
  509.         return (Socket *) GUSI_error_nil(ENOTCONN);
  510.  
  511.     if (nonblocking && pb->ioResult == 1)
  512.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  513.  
  514.     SPINP(Waiting(), SP_MISC, 0);
  515.  
  516.     if (pb->ioResult)
  517.         return (Socket *) GUSI_error_nil(EFAULT);
  518.  
  519.     newsock    =    new ADSPSocket(socket);
  520.  
  521.     if (!newsock)
  522.         return (Socket *) GUSI_error_nil(ENOMEM);
  523.     if (newsock->Init())
  524.         return (Socket *) nil;
  525.  
  526.     newsock->pb->csCode                            =    dspOpen;
  527.     newsock->pb->ioCompletion                    =    nil;
  528.     newsock->pb->u.openParams                    =    pb->u.openParams;
  529.     newsock->pb->u.openParams.ocMode            =    ocAccept;
  530.     newsock->pb->u.openParams.ocInterval    =    0;
  531.     newsock->pb->u.openParams.ocMaximum        =    0;
  532.     PBControlAsync(ParmBlkPtr(newsock->pb));
  533.  
  534.     SAFESPIN(newsock->Waiting(), SP_MISC, 0);
  535.  
  536.     pb->csCode                                =    dspCLListen;
  537.     pb->ioCompletion                        =    nil;
  538.     pb->u.openParams.filterAddress    =    NoFilter;
  539.  
  540.     PBControlAsync(ParmBlkPtr(pb));
  541.  
  542.     if (errno || newsock->pb->ioResult)    {
  543.         delete newsock;
  544.  
  545.         return (Socket *) (errno ? nil : GUSI_error_nil(ECONNREFUSED));
  546.     }
  547.  
  548.     if (address && addrlen)    {
  549.         addr.family    =    AF_APPLETALK;
  550.         addr.addr    =    pb->u.openParams.remoteAddress;
  551.  
  552.         memcpy(address, &addr, *addrlen = min(*addrlen, sizeof(sockaddr_atlk)));
  553.     }
  554.  
  555.     return newsock;
  556. }
  557.  
  558. int ADSPSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  559. {
  560.     if (from)
  561.         getpeername(from, fromlen);
  562.     if (flags & ~MSG_OOB)
  563.         return GUSI_error(EOPNOTSUPP);
  564.     if (!pb)
  565.         return GUSI_error(ENOTCONN);
  566.  
  567.     if (pb->csCode == dspOpen && pb->ioResult)    {
  568.         if (pb->ioResult == 1)    {
  569.             if (nonblocking)
  570.                 return GUSI_error(EWOULDBLOCK);
  571.  
  572.             SPIN(Waiting(), SP_MISC, 0);
  573.         }
  574.  
  575.         if (pb->ioResult)
  576.             return GUSI_error(ECONNREFUSED);
  577.     }
  578.  
  579.     if (flags & MSG_OOB)
  580.         if (ccb->userFlags & eAttention)    {
  581.             memcpy(Ptr(buffer), ccb->attnPtr, buflen = min(buflen, ccb->attnSize));
  582.  
  583.             ccb->userFlags ^= eAttention;
  584.  
  585.             return buflen;
  586.         } else
  587.             return GUSI_error(EINVAL);
  588.  
  589.     pb->csCode            =    dspStatus;
  590.  
  591.     PBControlSync(ParmBlkPtr(pb));
  592.  
  593.     if (!pb->u.statusParams.recvQPending)
  594.         if (nonblocking)
  595.             return GUSI_error(EWOULDBLOCK);
  596.         else if (readShutDown)
  597.             return 0;
  598.  
  599.     while (!pb->u.statusParams.recvQPending && Up()) {
  600.         SPIN(0, SP_STREAM_READ, 0);
  601.         PBControlSync(ParmBlkPtr(pb));
  602.     }
  603.  
  604.     pb->csCode                    =    dspRead;
  605.     pb->u.ioParams.reqCount    =    min(buflen, pb->u.statusParams.recvQPending);
  606.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  607.  
  608.     if (PBControlSync(ParmBlkPtr(pb)))
  609.         readShutDown = true;
  610.  
  611.     return pb->u.ioParams.actCount;
  612. }
  613.  
  614. int ADSPSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  615. {
  616.     if (to)
  617.         return GUSI_error(EOPNOTSUPP);
  618.     if (flags & ~MSG_OOB)
  619.         return GUSI_error(EOPNOTSUPP);
  620.     if (!pb)
  621.         return GUSI_error(ENOTCONN);
  622.  
  623.     if (pb->csCode == dspOpen && (pb->ioResult || !Up()))    {
  624.         if (Waiting())    {
  625.             if (nonblocking)
  626.                 return GUSI_error(EWOULDBLOCK);
  627.  
  628.             SPIN(Waiting(), SP_MISC, 0);
  629.         }
  630.  
  631.         if (pb->ioResult)
  632.             return GUSI_error(ECONNREFUSED);
  633.     }
  634.  
  635.     if (writeShutDown)
  636.             return GUSI_error(ESHUTDOWN);
  637.  
  638.     if (flags & MSG_OOB)    {
  639.         if (buflen < 0 || buflen > 570)
  640.             return GUSI_error(EINVAL);
  641.  
  642.         pb->csCode                        =    dspAttention;
  643.         pb->u.attnParams.attnCode    =    0;
  644.         pb->u.attnParams.attnSize    =    buflen;
  645.         pb->u.attnParams.attnData    =    (unsigned char *) buffer;
  646.  
  647.         PBControlSync(ParmBlkPtr(pb));
  648.  
  649.         if (pb->ioResult)
  650.             return GUSI_error(EINVAL);
  651.         else
  652.             return buflen;
  653.     }
  654.  
  655.     if (nonblocking)    {
  656.         pb->csCode    =    dspStatus;
  657.  
  658.         PBControlSync(ParmBlkPtr(pb));
  659.  
  660.         if (!pb->u.statusParams.sendQFree)
  661.             return GUSI_error(EWOULDBLOCK);
  662.     }
  663.  
  664.     pb->csCode                    =    dspWrite;
  665.     pb->u.ioParams.reqCount    =
  666.         nonblocking
  667.             ?     min(buflen, pb->u.statusParams.sendQFree)
  668.             :    buflen;
  669.     pb->u.ioParams.dataPtr    =    (u_char *) buffer;
  670.     pb->u.ioParams.eom        =    false;
  671.     pb->u.ioParams.flush        =    true;
  672.  
  673.     PBControlAsync(ParmBlkPtr(pb));
  674.  
  675.     SPIN(Waiting(), SP_STREAM_WRITE, 0);
  676.  
  677.     if (pb->ioResult)
  678.         writeShutDown = true;
  679.  
  680.     return pb->u.ioParams.actCount;
  681. }
  682.  
  683. int ADSPSocket::shutdown(int how)
  684. {
  685.     if (how < 0 || how > 2)
  686.         return GUSI_error(EINVAL);
  687.  
  688.     if (how)
  689.         writeShutDown    =    true;
  690.     if (!(how & 1))
  691.         readShutDown    =    true;
  692.  
  693.     return 0;
  694. }
  695.  
  696. int ADSPSocket::ioctl(unsigned int request, void *argp)
  697. {
  698.     switch (request)    {
  699.     case FIONREAD:
  700.         if (!pb)
  701.             return GUSI_error(ENOTCONN);
  702.  
  703.         pb->csCode            =    dspStatus;
  704.  
  705.         PBControlSync(ParmBlkPtr(pb));
  706.  
  707.         *(unsigned long *) argp    = pb->u.statusParams.recvQPending;
  708.  
  709.         return 0;
  710.     default:
  711.         return AppleTalkSocket::ioctl(request, argp);
  712.     }
  713. }
  714.  
  715. int ADSPSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  716. {
  717.     int    goodies = 0;
  718.  
  719.     if (pb) {
  720.         pb->csCode        =    dspStatus;
  721.         PBControlSync(ParmBlkPtr(pb));
  722.     }
  723.     
  724.     if (canRead)
  725.         if ( !pb || readShutDown || !Up() || pb->u.statusParams.recvQPending
  726.             ||    (pb->csCode == dspCLListen && pb->ioResult != 1)
  727.         )    {
  728.             *canRead = true;
  729.             ++goodies;
  730.         }
  731.  
  732.     if (canWrite)
  733.         if ( !pb || writeShutDown || !Up() || pb->u.statusParams.sendQFree != 0
  734.             || (pb->csCode == dspOpen && pb->ioResult != 1)
  735.         )    {
  736.             *canWrite = true;
  737.             ++goodies;
  738.         }
  739.         
  740.     if (exception && (ccb->userFlags & eAttention)) {
  741.         *exception = true;
  742.         ++goodies;
  743.     }
  744.  
  745.     return goodies;
  746. }
  747.  
  748. /********************* AppleTalkSocketDomain members **********************/
  749.  
  750. extern "C" void GUSIwithAppleTalkSockets()
  751. {
  752.     AppleTalkSockets.DontStrip();
  753. }
  754.  
  755. AppleTalkSocketDomain::AppleTalkSocketDomain()
  756.     :    SocketDomain(AF_APPLETALK)
  757. {
  758.     dspRefNum    =    0;
  759.     node.aNet    =    -1;
  760.     node.aNode    =    0;
  761.     node.aSocket=    0;
  762. }
  763.  
  764. void AppleTalkSocketDomain::DoMPPOpen()
  765. {
  766.     short    myNode;
  767.     short    myNet;
  768.  
  769.     if (AppleTalkIdentity(myNet, myNode))    {
  770.         node.aNet    =    -1;
  771.         node.aNode    =    0;
  772.         node.aSocket=    0;
  773.     } else {
  774.         node.aNet    =    myNet;
  775.         node.aNode    =    (u_char) myNode;
  776.         node.aSocket=    1;
  777.     }
  778. }
  779.  
  780. Boolean AppleTalkSocketDomain::Validate()
  781. {
  782.     if (!node.aSocket)
  783.         DoMPPOpen();
  784.  
  785.     return node.aSocket != 0;
  786. }
  787.  
  788. short    AppleTalkSocketDomain::GetDSP()
  789. {
  790.     if (!dspRefNum)
  791.         if (OpenDriver("\p.DSP", &dspRefNum))
  792.             dspRefNum    =    0;
  793.  
  794.     return dspRefNum;
  795. }
  796.  
  797. Socket * AppleTalkSocketDomain::socket(int type, short)
  798. {
  799.     AppleTalkSocket * sock    =    nil;
  800.  
  801.     errno    =    0;
  802.  
  803.     if (!Validate())
  804.         GUSI_error(ENETDOWN);
  805.     else
  806.         switch (type)    {
  807.         case SOCK_STREAM:
  808.             sock = new ADSPSocket();
  809.             break;
  810.         default:
  811.             GUSI_error(ESOCKTNOSUPPORT);
  812.         }
  813.  
  814.     if (sock && errno)    {
  815.         delete sock;
  816.  
  817.         return nil;
  818.     } else
  819.         return sock;
  820. }
  821.  
  822. int AppleTalkSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  823. {
  824.     sa_constr_atlk *     constr = (sa_constr_atlk *) constraint;
  825.     Point                    where;
  826.     NBPReply                reply;
  827.     sockaddr_atlk        addr;
  828.     char *                end;
  829.     Str255                promp;
  830.     NLType                dummy;
  831.  
  832.     if (!hasStdNBP)
  833.         return GUSI_error(EOPNOTSUPP);
  834.  
  835.     if (!Validate())
  836.         return GUSI_error(ENETDOWN);
  837.  
  838.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  839.         return GUSI_error(EINVAL);
  840.         
  841.     SetPt(&where, 100, 100);
  842.  
  843.     memset(&reply.theEntity, 0, sizeof(EntityName));
  844.     memcpy(&reply.theEntity.zoneStr, "\p*", 2);
  845.  
  846.     end         =     (char *) memccpy(promp+1, prompt, 0, 254);
  847.     promp[0]    =    end-(char *)promp-2;
  848.  
  849.     if (
  850.         StandardNBP(
  851.             where,
  852.             promp,
  853.             constr ? constr->numTypes : -1,
  854.             constr ? constr->types : dummy,
  855.             (NameFilterProcPtr) nil,
  856.             (ZoneFilterProcPtr) nil,
  857.             (DlgHookProcPtr) nil,
  858.             &reply)
  859.         != nlOk
  860.     )
  861.         return GUSI_error(EINTR);
  862.  
  863.     addr.family    =    AF_APPLETALK;
  864.     addr.addr    =     reply.theAddr;
  865.  
  866.     memcpy(name, &addr, *namelen = min(*namelen, sizeof(sockaddr_atlk)));
  867.  
  868.     return 0;
  869. }
  870.  
  871. /*********************** AtlkSymAddr members ************************/
  872.  
  873. static int EntityLen(const EntityName & name)
  874. {
  875.     Ptr    nm    =    Ptr(&name);
  876.     int    l1    =    *nm+1;
  877.     nm += l1;
  878.     int    l2    =    *nm+1;
  879.     nm += l2;
  880.     int    l3    =    *nm+1;
  881.  
  882.     return l1+l2+l3;
  883. }
  884.  
  885. AtlkSymAddr::AtlkSymAddr(const EntityName & name)
  886. {
  887.     int                len    =    EntityLen(name);
  888.  
  889.     errno = 0;
  890.  
  891.     if (!AppleTalkSockets.Validate())    {
  892.         GUSI_error(ENETDOWN);
  893.  
  894.         return;
  895.     }
  896.  
  897.     nte    =    (NTE *) NewPtr(9+len);
  898.     legit    =    false;
  899.  
  900.     if (!nte)    {
  901.         GUSI_error(ENOMEM);
  902.  
  903.         return;
  904.     }
  905.  
  906.     nte->next            =    nil;
  907.     memcpy(&nte->name, &name, len);
  908. }
  909.  
  910. void AtlkSymAddr::Register(u_char socket)
  911. {
  912.     MPPParamBlock    mpp;
  913.  
  914.     errno = 0;
  915.  
  916.     nte->addr.aSocket    =    socket;
  917.  
  918.     mpp.NBPinterval    =    8;
  919.     mpp.NBPcount        =    3;
  920.     mpp.NBPntQElPtr    =    Ptr(nte);
  921.     mpp.NBPverifyFlag    =    true;
  922.     PRegisterName(&mpp, false);
  923.  
  924.     if (mpp.MPPioResult)    {
  925.         DisposPtr(Ptr(nte));
  926.  
  927.         GUSI_error((mpp.MPPioResult == nbpDuplicate) ? EADDRINUSE : EFAULT);
  928.     } else
  929.         legit    =    true;
  930. }
  931.  
  932. AtlkSymAddr::~AtlkSymAddr()
  933. {
  934.     if (nte)    {
  935.         if (legit) {
  936.             MPPParamBlock    mpp;
  937.  
  938.             mpp.NBPentityPtr    =    Ptr(&nte->name);
  939.             PRemoveName(&mpp, false);
  940.         }
  941.  
  942.         DisposPtr(Ptr(nte));
  943.     }
  944. }
  945.  
  946. static int AtlkLookup(const EntityName & name, AddrBlock * addr)
  947. {
  948.     EntityName        ent;
  949.     char                found[256];
  950.     MPPParamBlock    mpp;
  951.  
  952.     mpp.NBPinterval        =    8;
  953.     mpp.NBPcount            =    3;
  954.     mpp.NBPentityPtr        =    Ptr(&name);
  955.     mpp.NBPretBuffPtr        =    found;
  956.     mpp.NBPretBuffSize    =    256;
  957.     mpp.NBPmaxToGet        =    1;
  958.     PLookupName(&mpp, false);
  959.     if (!mpp.MPPioResult)
  960.         NBPExtract(found, mpp.NBPnumGotten, 1, &ent, addr);
  961.  
  962.     if (mpp.MPPioResult)
  963.         return GUSI_error(EADDRNOTAVAIL);
  964.  
  965.     return 0;
  966. }
  967.